/*
 * @Date         : 2022-03-01 13:26:38
 * @LastEditors  : zu1662
 * @LastEditTime : 2022-03-03 19:45:08
 * @Description  : 字体打印主功能类
 * 
 * Copyright © 2022 by zu1662, All Rights Reserved. 
 */
/* eslint-disable */
class Typing {
  public opts:any;
  public chain:any;
  constructor (opts:any) {
    this.opts = opts || { delay: 120 }
    this.chain = {
      parent: null,
      dom: this.opts.output,
      val: []
    }
    if (!(typeof this.opts.done === 'function')) {
      this.opts.done = function () {
      }
    }
  }

  init () {
    // 初始化函数
    this.chain.val = this.convert(this.opts.source, this.chain.val)
  }

  convert (dom: any, arr: any[]) {
    // 将dom节点的子节点转换成数组，
    const children = Array.from(dom.childNodes)
    for (let i = 0; i < children.length; i++) {
      const node = children[i] as HTMLElement
      if (node['nodeType'] === 3) {
        if(node['nodeValue']) {
          arr = arr.concat(node['nodeValue'].split('')) // 将字符串转换成字符串数组，后面打印时才会一个一个的打印
        }
      } else if (node['nodeType'] === 1) {
        let val: any[] = []
        val = this.convert(node, val)
        arr.push({
          dom: node,
          val: val
        })
      }
    }
    return arr
  }

  print (dom:any, val: any, callback: any) {
    setTimeout(function () {
      dom.appendChild(document.createTextNode(val))
      callback()
    }, this.opts.delay)
  }

  play (ele: any) {
    // 当打印最后一个字符时，动画完毕，执行done
    if (!ele.val.length) {
      if (ele.parent) this.play(ele.parent)
      else this.opts.done()
      return
    }
    const current = ele.val.shift() // 获取第一个元素，同时删除数组中的第一个元素
    if (typeof current === 'string') {
      this.print(ele.dom, current, () => {
        this.play(ele) // 继续打印下一个字符
      })
    } else {
      const dom = current.dom.cloneNode() // 克隆节点，不克隆节点的子节点，所以不用加参数true
      ele.dom.appendChild(dom)
      this.play({
        parent: ele,
        dom,
        val: current.val
      })
    }
  }

  start () {
    this.init()
    this.play(this.chain)
  }
}

export default Typing
